package com.service.component.common;

import com.alibaba.fastjson.JSON;
import com.service.component.common.swagger.SwaggerConfig;
import org.apache.commons.collections.map.LinkedMap;
import org.apache.commons.lang3.StringUtils;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger.web.ApiResourceController;
import springfox.documentation.swagger.web.UiConfiguration;
import springfox.documentation.swagger2.web.Swagger2Controller;

import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;



// 切面bean,统一替换.
/**
 * webflux响应信息统一切换
 */
/*@Aspect
@Component
@ConditionalOnClass(name = {"org.springframework.web.reactive.result.method.annotation.ResponseBodyResultHandler"})
public class ResponseBodyResultHandlerAspect {

    @SneakyThrows
    @Around(value = "execution(* org.springframework.web.reactive.result.method.annotation.ResponseBodyResultHandler.handleResult(..)) && args(exchange, result)", argNames = "point,exchange,result")
    public Object handleResult(ProceedingJoinPoint point, ServerWebExchange exchange, HandlerResult result) {
        final Mono responseMono = ((Mono) result.getReturnValue()).map(responseValue -> responseValue instanceof ResponseInfo ? responseValue : ResponseInfo.ok(responseValue));
        return point.proceed(Arrays.asList(
                exchange,
                new HandlerResult(result.getHandler(), responseMono, result.getReturnTypeSource())
        ).toArray());
    }
}*/

@ControllerAdvice
/**
 * @author ：Calvin
 * @date ：Created in 2021/7/16 14:35
 * @description：全局返回结果处理
 * @modified By：
 * @version: 1.0.0$
 */
public class CommonResponseAdvice implements ResponseBodyAdvice {
    /**
     * 对于哪些请求要执行beforeBodyWrite，返回true执行，返回false不执行
     *
     * @param methodParameter 方法参数
     * @param aClass          类
     * @return 是否执行beforeBodyWrite
     */
    @Override
    public boolean supports(MethodParameter methodParameter, Class aClass) {
        //由于swagger和全局返回处理格式会冲突，所以需要对其过滤
        if (StringUtils.containsIgnoreCase(methodParameter.getDeclaringClass().getName(),"swagger") ||methodParameter.getDeclaringClass().equals(ApiResourceController.class) || methodParameter.getDeclaringClass().equals(Swagger2Controller.class)) {
            return false;
        }
        return true;
    }

    /**
     * 对于返回的对象如果不是最终对象CommonResult，则选包装一下
     *
     * @param o                  返回信息
     * @param methodParameter    方法参数
     * @param mediaType          类型
     * @param aClass             类
     * @param serverHttpRequest  serverHttpRequest
     * @param serverHttpResponse serverHttpResponse
     * @return 返回包装后的数据
     */
    @Override
    public Object beforeBodyWrite(Object o, MethodParameter methodParameter, MediaType mediaType, Class aClass, ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) {
        if (o instanceof CommonResult) {
            return o;
        } else {
            /**
             * Springmvc内部定义了九个不同的MessageConverter用来处理不同的返回值。在AbstractMessageConverterMethodProcessor
             * 类下面的writeWithMessageConverters方法可以看出来，每个MessageConverer是根据返回类型和媒体类型
             * 来选择处理的MessageConverter的,因为handler处理类的返回类型是String，为了保证一致性，
             * 这里需要将ResponseResult转回去
             */
            if (o == null || o instanceof String || o instanceof UiConfiguration) {
                return JSON.toJSONString(CommonResult.success(o));
            }
            if(o instanceof HashMap){
                if(((HashMap<?, ?>) o).containsKey("status") &&StringUtils.containsIgnoreCase(((HashMap<?, ?>) o).get("status").toString(),"404")){
                   return CommonResult.commonResult(CommonResult.ResultCode.UNAUTHENTICATED_OR_NOT_FOUND_ERROR);
                }
            }
            return CommonResult.success(o);
        }
    }
}
